package com.hj.springframework3.utils;

import cn.hutool.core.util.StrUtil;
import com.hj.springframework3.annotation.Bean;
import com.hj.springframework3.annotation.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.Nullable;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * @Author : hujing
 * @Date: 2025/7/4 16:57
 * @Description:
 */
public class ClassUtils {

    final static Logger logger = LoggerFactory.getLogger(ClassUtils.class);

    /**
     * 递归查找目标注解上是否有annoClass类型注解,比如在类上查找@Component注解，如果目标类上是标的@Service注解，则需要@Service上是否有@Component注解
     * @param target
     * @param annoClass
     * @return
     * @param <A>
     */
    public static <A extends Annotation> A findAnnotation(Class<?> target, Class<A> annoClass) {
        A a = target.getAnnotation(annoClass);
        for (Annotation anno : target.getAnnotations()) {
            Class<? extends Annotation> annoType = anno.annotationType();
            if (!annoType.getPackageName().equals("java.lang.annotation")) {
                // 递归查找
                A found = findAnnotation(annoType, annoClass);
                if (found != null) {
                    if (a != null) {
                        throw new IllegalArgumentException("重复的注解:" + annoClass.getSimpleName());
                    }
                    a = found;
                }
            }
        }
        return a;
    }

    /**
     * Get bean name by:
     *
     * <code>
     *
     * @Bean Hello createHello() {}
     * </code>
     */
    public static String getBeanName(Method method) {
        Bean bean = method.getAnnotation(Bean.class);
        String name = bean.value();
        if (name.isEmpty()) {
            name = method.getName();
        }
        return name;
    }

    public static String getBeanName(Class<?> clazz) {
        String name = "";
        // 查找@Component注解
        Component component = clazz.getAnnotation(Component.class);
        if (component != null) {
            name = component.value();
        } else {
            // 未找到@Component注解，继续在其他注解中找@Component注解
            for (Annotation annotation : clazz.getAnnotations()) {
                if (findAnnotation(annotation.annotationType(), Component.class) != null) {
                    try {
                        name = (String) annotation.annotationType().getMethod("value").invoke(annotation);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }

        // 以上都未找到，则使用类名，首字母小写作为bean的名称
        if (name.isEmpty()) {
            // default name: "HelloWorld" => "helloWorld"
            name = clazz.getSimpleName();
            // 首字母小写
            name = name.substring(0, 1).toLowerCase() + name.substring(1);
        }

        return name;
    }

    /**
     * 通过 @PostConstruct 或 @PreDestroy 获取无参方法。不在父类中查找
     *
     * <code>
     *
     * @PostConstruct void init() {}
     * </code>
     */
    @Nullable
    public static Method findAnnotationMethod(Class<?> clazz, Class<? extends Annotation> annoClass) {
        List<Method> collect = Arrays.stream(clazz.getDeclaredMethods()).filter(method -> method.isAnnotationPresent(annoClass)).map(method -> {
            if (method.getParameterCount() != 0) {
                logger.error("注解方法{}参数数量不为0", method.getName());
            }
            return method;
        }).toList();
        if (collect.isEmpty()) {
            return null;
        }
        if (collect.size() == 1) {
            return collect.get(0);
        }
        return null;
    }

    /**
     * 在注解数组中查找指定类型注解
     * @param annos
     * @param annoClass
     * @return
     * @param <A>
     */
    @Nullable
    public static <A extends Annotation> A getAnnotation(Annotation[] annos, Class<A> annoClass) {
        for (Annotation anno : annos) {
            if (annoClass.isInstance(anno)){
                return (A) anno;
            }
        }
        return null;
    }
    
    public static Method getNamedMethod(Class<?> clazz,String methodName){
        if (StrUtil.isEmpty(methodName)){
            return null;
        }
        
        try{
            return clazz.getDeclaredMethod(methodName);
        }catch (Exception e){
            logger.error("获取方法失败",e);
        }
        return null;
    }
}
